import processing.video.*;

boolean videoCapturingOn = false;
int numPixels;
int[] previousFrame;
int frameCounter = 0;
float motionCalibrationValue = 0.0;
float currentMotionCalibrationTime = 0.0;
float frameDifference = 0.0;
float totalFrameDifference = 0.0;
final float LEARNING_RATE = 0.95;
Capture video;

void setupMotionDetection() {
  try {
    video = new Capture(this, width, height, 24);
    //println(video.list());
    numPixels = video.width * video.height;
    previousFrame = new int[numPixels];
    loadPixels();
    videoCapturingOn = true;
  } 
  catch(Exception e) {
    println("No video capturing device found!");
  }
}

void handleMotionDetection() {
  if(!videoCapturingOn)
    return;

  frameDifference = 0;
  color white = color(255,255,255);
  color black = color(0,0,0);
  int movementSum = 0;
  int totalMovementSum = 0;
  if (video.available()) {
    video.read();
    video.loadPixels();

    for (int i = 0; i < numPixels; i++) {
      color currentColor = video.pixels[i];
      color previousColor = previousFrame[i];

      int currentR = (currentColor >> 16) & 0xFF;
      int currentG = (currentColor >> 8) & 0xFF;
      int currentB = currentColor & 0xFF;
      int previousR = (previousColor >> 16) & 0xFF;
      int previousG = (previousColor >> 8) & 0xFF;
      int previousB = previousColor & 0xFF;

      int diffR = abs(currentR - previousR);
      int diffG = abs(currentG - previousG);
      int diffB = abs(currentB - previousB);

      movementSum = abs(diffR + diffG + diffB);
      totalMovementSum += movementSum;

      if(movementSum > MOVEMENT_THRESHOLD) {    
        previousFrame[i] = (int)((LEARNING_RATE *currentColor) + ((1-LEARNING_RATE)* previousFrame[i]));
        frameDifference += 1.0;
        if(state == ViewMotionDetection) {
          pixels[i] = currentColor;
        }
      }
      else {      
        previousFrame[i] = previousFrame[i];
        if(state == ViewMotionDetection) {
          //pixels[i] = currentColor;
          pixels[i] = black;
        }
      }
    }

    // Check that the frame was not totally black (flickering)
    if (totalMovementSum > 0) {
      totalFrameDifference += frameDifference;
      frameCounter++;
      if(state == ViewMotionDetection) {
        updatePixels();
      }
    }
  }
}


public void motionDetectionCalibration() {
  if(!videoCapturingOn)
    return;
      
  if(state != RatingImage && state != ShowResult) {
    currentMotionCalibrationTime += dt;
    
    if(currentMotionCalibrationTime >= CALIBRATION_TIME) {
      if(motionCalibrationValue < CALIBRATION_UPPER_LIMIT) {
        motionCalibrationValue = (totalFrameDifference/numPixels)/frameCounter;

      }
      else {
        motionCalibrationValue = CALIBRATION_UPPER_LIMIT;
      }
      currentMotionCalibrationTime = 0;
      totalFrameDifference = 0.0;
      frameCounter = 0;
    }
  }
  else {
      currentMotionCalibrationTime = 0;
    }
}


void startMotionDetectionRating() {
  totalFrameDifference = 0.0;
  frameCounter = 0;
}

public float getMotionDetectionRating() {
  if(((totalFrameDifference/numPixels)/frameCounter) > motionCalibrationValue) {

    float rawMotionScore = ((((totalFrameDifference/numPixels)/frameCounter) - motionCalibrationValue)/(1 - motionCalibrationValue));
    float motionScore = ceil(map(rawMotionScore, 0, RAW_HIGH_MOTION_SCORE, LOW_SCORE, HIGH_SCORE));
        println(rawMotionScore);
    motionCalibrationValue = 0;  
    if(motionScore > HIGH_SCORE) {
      return HIGH_SCORE;
    }

    return motionScore;
  }
  else {
    motionCalibrationValue = 0;
    return LOW_SCORE;
  }
}

